package org.wattdepot.gdata.kukuicup.service;

import java.net.URL;
import java.text.DateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.gdata.kukuicup.GDataProperties;
import com.google.gdata.client.ClientLoginAccountType;
import com.google.gdata.client.spreadsheet.FeedURLFactory;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
import com.google.gdata.data.spreadsheet.SpreadsheetFeed;
import com.google.gdata.util.AuthenticationException;

/**
 * Provides access to the Google GData service, using the data in the provided properties file.
 * Also used to determine which updaters should run.   
 * @author Philip Johnson
 */
public class GDataService {
  /** The spreadsheet service. */
  private SpreadsheetService service = new SpreadsheetService("GDataService");
  /** The map that contains the URLs for the various spreadsheets. */  
  private Map<String, URL> spreadsheet2URL = new HashMap<String, URL>();
  
  /**
   * Initialize this instance from the passed properties file.
   * Throws a RuntimeException if the properties are not available. 
   * @param properties The properties for this run of the system.
   */
  public GDataService(GDataProperties properties) {
    // The properties file was found. Now get the required properties from it.
    String username = properties.getGDataUserName();
    String password = properties.getGDataPassword();
    String token = properties.getToken();
    
    // Authenticate using the credentials in the property file.
    try {
      if (token == null) {
        System.out.println("Logging in with username/password");
        service.setUserCredentials(username, password, ClientLoginAccountType.GOOGLE);
        // Remove printing of token for the time being. 
        //UserToken auth_token = (UserToken)service.getAuthTokenFactory().getAuthToken();
        //System.out.println("Google Authorization token is: " + auth_token.getValue());
      }
      else {
        System.out.println("Logging in using token.");
        service.setUserToken(token);
      }
    }
    catch (AuthenticationException e) {
      String msg = "Fatal error: Could not authenticate to Google.";
      System.out.println(msg);
      throw new RuntimeException(msg, e);
    }
    
    
    // Workaround: http://code.google.com/p/gdata-java-client/issues/detail?id=103
    service.setProtocolVersion(SpreadsheetService.Versions.V1);
  }

  /**
   * Returns the URL to the specified spreadsheet.
   * @param name The name of the spreadsheet.
   * @return The URL of the latest power spreadsheet.
   * @throws Exception If we can't find the spreadsheet.
   */
  public URL getSpreadsheetURL(String name) throws Exception {
    // If it's not in the cache, then add it.
    if (!this.spreadsheet2URL.containsKey(name)) {
      SpreadsheetEntry spreadsheetEntry = findSpreadsheet(name);
      URL url = spreadsheetEntry.getWorksheets().get(0).getCellFeedUrl();
      this.spreadsheet2URL.put(name, url);
    }
    // Now return the cached URL.
    return this.spreadsheet2URL.get(name);
  }
  

  /**
   * Returns the SpreadsheetEntry instance representing the spreadsheet named 'name'.
   * 
   * @param name The name of the spreadsheet to find. 
   * @return The SpreadsheetEntry.
   * @throws Exception If the spreadsheet with the specified name could not be found.
   */
  private SpreadsheetEntry findSpreadsheet(String name) throws Exception {
    // If not found, find the spreadsheet.
    FeedURLFactory factory = FeedURLFactory.getDefault();
    SpreadsheetFeed feed = service.getFeed(factory.getSpreadsheetsFeedUrl(), SpreadsheetFeed.class);
    List<SpreadsheetEntry> spreadsheets = feed.getEntries();
    SpreadsheetEntry spreadsheetEntry = null;
    for (SpreadsheetEntry entry : spreadsheets) {
      if (entry.getTitle().getPlainText().equalsIgnoreCase(name)) {
        spreadsheetEntry = entry;
      }
    }
    // If we couldn't find the spreadsheet specified in the properties file, throw an error.
    if (spreadsheetEntry == null) {
      throw new Exception("Could not find spreadsheet: " + name);
    }
    return spreadsheetEntry;
  }
  
  /**
   * Returns the spreadsheet service.
   * @return The spreadsheet service. 
   */
  public SpreadsheetService getSpreadsheetService() {
    return this.service;
  }
  
  /**
   * Returns the current time as a string in a format suitable for a Last Update column.
   * @return The current time as mm/dd/yyyy hh:mm:ss.
   */
  public String makeLastUpdate() {
    DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
    return dateFormat.format(new Date());
  }
  
  /**
   * Returns the passed timestamp as a string in a format suitable for a Last Update column.
   * @param timestamp The timestamp. 
   * @return The current time as mm/dd/yyyy hh:mm:ss.
   */
  public String makeLastUpdate(XMLGregorianCalendar timestamp) {
    DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
    Date date = timestamp.toGregorianCalendar().getTime();
    return dateFormat.format(date);
  }
} 
